#include "Cache.h"

Cache::Cache(int csize, 
             int cassoc, 
             int cbsize, 
             int caddressable, 
             const char * repPol, 
             bool cskew) {
  
  numReadHits = 0;
  numReadMisses = 0;

  numWriteHits = 0;
  numWriteMisses = 0;

  CacheGeneric<StateGeneric<> > *c = 
    CacheGeneric<StateGeneric<> >::create(csize, 
                                       cassoc, 
                                       cbsize, 
                                       caddressable, 
                                       repPol, 
                                       cskew);
  cache = (CacheGeneric<StateGeneric<>  >*)c; 

}

void Cache::dumpStatsToFile(FILE* outFile){
  fprintf(outFile, "-----Cache Stats-----\n");

  fprintf(outFile, "Read Hits:                   %d\n",numReadHits);
  fprintf(outFile, "Read Misses:                 %d\n",numReadMisses);

  fprintf(outFile, "Write Hits:                  %d\n",numWriteHits);
  fprintf(outFile, "Write Misses:                %d\n",numWriteMisses);

}

int Cache::getStateAsInt(unsigned long addr){
  return (int)this->cache->findLine(addr)->getState();
}

void Cache::readLine(uint32_t rdPC, uint32_t addr){
  /*
   *This method implements actions taken on a read access to address addr
   *at instruction rdPC
  */

  /*Get the state of the line to which this address maps*/
  StateGeneric<> *st = 
    (StateGeneric<> *)cache->findLine(addr);    
  
  /*Read Miss - tags didn't match, or line is invalid*/
  if(!st || (st && !(st->isValid())) ){

    /*Update event counter for read misses*/
    numReadMisses++;

    /*Fill the line*/
    fillLine(addr); 
      
  }else{

    /*Read Hit - any state but Invalid*/
    numReadHits++; 
    return; 

  }

}

void Cache::writeLine(uint32_t wrPC, uint32_t addr){
  /*This method implements actions taken when instruction wrPC
   *writes to memory location addr*/

  /*Find the line to which this address maps*/ 
  StateGeneric<> * st = (StateGeneric<> *)cache->findLine(addr);    
   
  /*
   *If the tags didn't match, or the line was invalid, it is a 
   *write miss
   */ 
  if(!st || (st && !(st->isValid())) ){ 

    numWriteMisses++;
    
    /*Fill the line with the new written block*/
    fillLine(addr);

    return;

  }else{ //Write Hit

    /*Already have it writable: No action required!*/
    numWriteHits++;

    return;

  }

}


void Cache::fillLine(uint32_t addr){

  //this gets the state of whatever line this address maps to 
  StateGeneric<> *st = (StateGeneric<> *)cache->findLine2Replace(addr); 

  if(st==0){
    /*No state*/
    return;
  }

  /*Set the tags to the tags for the newly cached block*/
  st->setTag(cache->calcTag(addr));

  return;
    
}


